package engine;

import java.util.Vector;

import sun.misc.Perf.GetPerfAction;

/**
 * class Move
 *
 * This class represents an individual piece move.  A portion of this class was originally taken from 
 *  Mediocre chess by Jonathan Peterson (particularly the notation portion)
 *  
 *
 * @author Brandon Ridenour (brandon.ridenour@gmail.com)
 * Date: 2007-2-18
 */

public class Move implements Constants
{
	public int pieceMoving; // Type of piece moving
	public int fromIndex; // The square the piece is moving from
	public int toIndex; // The square the piece is moving to	
	public int capture; // Value of the captured piece (0 if no capture)
	public int moveType; // ordinary, castling long/short, en passant
	public int[] prevPos; // An array with 4 places with information about previous position
			      // prevPos[0] = en passant
			      // prevPos[1] = white castle rights
			      // prevPos[2] = black castle rights
			      // prevPos[3] = half-moves
	public int capturedPieceIndex;		// holds the piece array index to the piece captured by the move
	public int moveScore;   // we will estimate the strength of the move for sorting

	/** *********************************** */	

	// Constructor with parameters
	public Move(
		int pieceMoving, int fromIndex, int toIndex,
		int capture, int moveType, int[] prevPos)
	{
		this.pieceMoving = pieceMoving;
		this.fromIndex = fromIndex;
		this.toIndex = toIndex;
		this.capture = capture;
		this.moveType = moveType;
		this.prevPos = prevPos;
		this.capturedPieceIndex = NO_CAPTURE;
	}

	/**
	 *  Returns a string holding the short notation of the move
	 *
	 *  @return String Short notation
	 */
	public String notation()
	{
		String notation = "";

		// Add the piece notation
		switch(pieceMoving)
		{
			case WHITE_KING:
				{
					if(moveType == SHORT_CASTLE) return "0-0";
					if(moveType == LONG_CASTLE) return "0-0-0";
					notation += "K"; break;
				}	
			case BLACK_KING:
				{
					if(moveType == SHORT_CASTLE) return "0-0";
					if(moveType == LONG_CASTLE) return "0-0-0";
					notation += "K"; break;
				}				
			case WHITE_QUEEN: notation += "Q"; break;
			case BLACK_QUEEN: notation += "Q"; break;
			case WHITE_ROOK: notation += "R"; break;
			case BLACK_ROOK: notation += "R"; break;
			case WHITE_BISHOP: notation += "B"; break;
			case BLACK_BISHOP: notation += "B"; break;
			case WHITE_KNIGHT: notation += "N"; break;
			case BLACK_KNIGHT: notation += "N"; break;
		}

		if(capture != 0) // The move is a capture
		{
			// If the moving piece is a pawn we need to add the row it's moving from
			if((pieceMoving == WHITE_PAWN) || (pieceMoving == BLACK_PAWN))
			{
				switch(fromIndex % 16) // Find the row
				{
					case 0: notation += "a"; break;
					case 1: notation += "b"; break;
					case 2: notation += "c"; break;
					case 3: notation += "d"; break;
					case 4: notation += "e"; break;
					case 5: notation += "f"; break;
					case 6: notation += "g"; break;
					case 7: notation += "h"; break;
				}
			}
			notation += "x";
		}

		switch(toIndex % 16) // Find the row
		{
			case 0: notation += "a"; break;
			case 1: notation += "b"; break;
			case 2: notation += "c"; break;
			case 3: notation += "d"; break;
			case 4: notation += "e"; break;
			case 5: notation += "f"; break;
			case 6: notation += "g"; break;
			case 7: notation += "h"; break;
		}

		notation += (toIndex-(toIndex%16))/16 + 1; // Add the rank
		
		if(moveType == EN_PASSANT)
			notation += " e.p.";

		// Add promotion
		switch(moveType)
		{
			case PROMOTION_QUEEN: notation += "=Q"; break;
			case PROMOTION_ROOK: notation += "=R"; break;
			case PROMOTION_BISHOP: notation += "=B"; break;
			case PROMOTION_KNIGHT: notation += "=N"; break;
		}
		
		return notation;
	}
	// END notation()
	
	/**
	 *  Returns the move on the form 'e2e4', that is
	 *  only the from and to square
	 *
	 *  @return String The input notation
	 */
	public String inputNotation()
	{
		String inputNotation = new String();
		switch(fromIndex%16)
		{
			case 0: inputNotation += "a"; break;
			case 1: inputNotation += "b"; break;
			case 2: inputNotation += "c"; break;
			case 3: inputNotation += "d"; break;
			case 4: inputNotation += "e"; break;
			case 5: inputNotation += "f"; break;
			case 6: inputNotation += "g"; break;
			case 7: inputNotation += "h"; break;
		}
		switch((fromIndex-(fromIndex%16))/16)
		{
			case 0: inputNotation += "1"; break;
			case 1: inputNotation += "2"; break;
			case 2: inputNotation += "3"; break;
			case 3: inputNotation += "4"; break;
			case 4: inputNotation += "5"; break;
			case 5: inputNotation += "6"; break;
			case 6: inputNotation += "7"; break;
			case 7: inputNotation += "8"; break;
		}
		switch(toIndex%16)
		{
			case 0: inputNotation += "a"; break;
			case 1: inputNotation += "b"; break;
			case 2: inputNotation += "c"; break;
			case 3: inputNotation += "d"; break;
			case 4: inputNotation += "e"; break;
			case 5: inputNotation += "f"; break;
			case 6: inputNotation += "g"; break;
			case 7: inputNotation += "h"; break;
		}
		switch((toIndex-(toIndex%16))/16)
		{
			case 0: inputNotation += "1"; break;
			case 1: inputNotation += "2"; break;
			case 2: inputNotation += "3"; break;
			case 3: inputNotation += "4"; break;
			case 4: inputNotation += "5"; break;
			case 5: inputNotation += "6"; break;
			case 6: inputNotation += "7"; break;
			case 7: inputNotation += "8"; break;
		}    
		switch(moveType) // Check for promotion
		{
			case PROMOTION_QUEEN: inputNotation += "q"; break;
			case PROMOTION_ROOK: inputNotation += "r"; break;
			case PROMOTION_BISHOP: inputNotation += "b"; break;
			case PROMOTION_KNIGHT: inputNotation += "n"; break;
		}		

		return inputNotation;

	}
	// END inputNotation()

	/**
	 * Generates a preliminary value score for the move that will be used in sorting the search
	 * tree.
	 * @param chessboard
	 */
	public void updateScore(Chessboard board) {
		
		// lets first set a score based on whether or not the move is an attempted capture,
		// and the value difference between attacker and attackee
		int score=0;
		Vector defenders = null;
		
		if (board.toMove == WHITE_TO_MOVE)
			defenders = board.blackPieces;
		else
			defenders = board.whitePieces;
		
		Piece defender = null;
		int defIndex = board.boardArray[toIndex]; 
				
		if(defIndex != EMPTY_SQUARE){
			// this is an attempted capture, lets update the score appropriately
			defender = (Piece)board.getPieceFromArray(defIndex, defenders);
			
			// we switch the attacking piece with toMove to make the switch statement simpler
			score += getCaptureScoreValue((pieceMoving*board.toMove), defender.piece_type);
			
		}
		else if(moveType == EN_PASSANT)
			score += 10;
		else if(moveType == CASTLE_LONG || moveType == CASTLE_SHORT)
			score +=100;
		//else if(pieceMoving == WHITE_PAWN || pieceMoving ==BLACK_PAWN)
			//score += 3;
		
		this.moveScore = score;
		
		
	}

	/**
	 * @param pieceMoving2
	 * @param piece_type
	 * @return
	 */
	private int getCaptureScoreValue(int attackingPieceType, int defendingPieceType) {
		
		int score = 0;
		
		switch(defendingPieceType) 
		{
			case WHITE_QUEEN:
			case BLACK_QUEEN:
				switch(attackingPieceType)
				{
					case WHITE_QUEEN:  score = 10; break;
					case WHITE_ROOK:  score = 20; break;
					case WHITE_BISHOP:  score = 30; break;
					case WHITE_KNIGHT:  score = 30; break;
					case WHITE_KING:  score = 0; break;
					case WHITE_PAWN:  score = 50; break;
				}
				
			case WHITE_ROOK: 
			case BLACK_ROOK:
				switch(attackingPieceType)
				{
					case WHITE_QUEEN:  score = 5; break;
					case WHITE_ROOK:  score = 10; break;
					case WHITE_BISHOP:  score = 20; break;
					case WHITE_KNIGHT:  score = 20; break;
					case WHITE_KING:  score = 1; break;
					case WHITE_PAWN:  score = 30; break;
				}
				
			case WHITE_BISHOP: 
			case BLACK_BISHOP:
			case WHITE_KNIGHT: 
			case BLACK_KNIGHT:
				switch(attackingPieceType)
				{
					case WHITE_QUEEN:  score = 5; break;
					case WHITE_ROOK:  score = 7; break;
					case WHITE_BISHOP:  score = 10; break;
					case WHITE_KNIGHT:  score = 10; break;
					case WHITE_KING:  score = 1; break;
					case WHITE_PAWN:  score = 20; break;
				}
							
				
			case WHITE_KING:
			case BLACK_KING:
				switch(attackingPieceType)
				{
					case WHITE_QUEEN:  score = 100; break;
					case WHITE_ROOK:  score = 90; break;
					case WHITE_BISHOP:  score = 80; break;
					case WHITE_KNIGHT:  score = 80; break;
					case WHITE_KING:  score = 0; break;
					case WHITE_PAWN:  score = 70; break;
				}
				       
			case WHITE_PAWN:
			case BLACK_PAWN:
				switch(attackingPieceType)
				{
					case WHITE_QUEEN:  score = 2; break;
					case WHITE_ROOK:  score = 2; break;
					case WHITE_BISHOP:  score = 5; break;
					case WHITE_KNIGHT:  score = 5; break;
					case WHITE_KING:  score = 1; break;
					case WHITE_PAWN:  score = 10; break;
				}
		}			
		return score;
	}

	
}
